﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using Vowei.Core.Models;

using Vowei.Data.Helpers;
using System.Diagnostics;

namespace vowei.specs
{
    [Binding]
    public class FeatureImpl : SpecTestBase
    {
        private string _requirementTitle;
        private Project _project;
        private List<Ticket> _expectedChildren = new List<Ticket>();

        private string _projectTitle;
        private string _defaultProjectOwner = "HW-YISH-2\\Administrator";
        private int _projectMilestoneCount = 0;

        [BeforeScenario]
        public void CreateANewProjectForTest()
        {
            base.BeforeTestRun();
            _project = CreateProjectFromContext();
            _expectedChildren.Clear();
        }

        [Given(@"I am on the create project page")]
        public void GivenIAmOnTheCreateProjectPage()
        {
            Selenium.Open("/");
            Selenium.Click("link=创建项目");
            WaitPageToLoad();
        }

        [Given(@"Fill all necessary project properties")]
        public void GivenFillAllNecessaryProjectProperties()
        {
            _projectTitle = Guid.NewGuid().ToString();
            Selenium.Type("Title", _projectTitle);
            Selenium.Type("Owner", _defaultProjectOwner);
            Selenium.Click("StartDate");
            Selenium.Click("link=14");
            Selenium.Click("DueDate");
            Selenium.Click("link=28");
        }

        [When(@"I press create on project page")]
        public void WhenIPressCreateOnProjectPage()
        {
            Selenium.Click("submit_btn");
            WaitPageToLoad();
        }

        [Given(@"Added some milestones")]
        public void GivenAddedSomeMilestones()
        {
            var random = new Random();
            while (_projectMilestoneCount == 0)
                _projectMilestoneCount = random.Next(2);

            for (int i = 0; i < _projectMilestoneCount; ++i)
            {
                var title = string.Format("Milestone {0}", i + 1);
                Selenium.Click("createRelatedObject");
                WaitAjaxToFinish();
                Selenium.Type("Milestone_Title", title);
                Selenium.Click("Milestone_StartDate");
                Selenium.Click("link=21");
                Selenium.Click("Milestone_DueDate");
                Selenium.Click("link=25");
                Selenium.Click("//button[@type='button']");
                WaitAjaxToFinish();
            }
        }

        [Then(@"A project should be created")]
        public void ThenAProjectShouldBeCreated()
        {
            var projects = ProductContext.Projects.Query.Where(
                p => p.Title == _projectTitle);
            Assert.AreNotEqual(0, projects.Count());

            var project = projects.First();
            Assert.AreEqual(_defaultProjectOwner, project.Owner);
        }

        [Then(@"Milestones are added to the project")]
        public void ThenMilestonesAreAddedToTheProject()
        {
            var projects = ProductContext.Projects.Include("Children").Query.Where(
                p => p.Title == _projectTitle);
            var project = projects.First();

            Assert.AreEqual(_projectMilestoneCount, project.Children.Count());
        }

        [Given(@"I selected a project")]
        public void GivenISelectedAProject()
        {
            _projectTitle = _project.Title;
            Selenium.Open(string.Format("/Project/Details/{0}", _project.ID.ToString("N")));
            WaitPageToLoad();
        }

        [When(@"I choosed a task spreadsheet to import")]
        public void WhenIChoosedATaskSpreadsheetToImport()
        {
            Selenium.Click("link=导入任务");
            WaitPageToLoad();

            var excelPath =
                "C:\\workspace\\src\\vowei.test\\TestData\\StatisticsHelpersTest_TopRequirementWorksBasicTest.xls";
            Selenium.Type("TicketsSpreadsheet", excelPath);
            Selenium.Click("//input[@value='提交']");
            Selenium.Click("//input[@value='确认']");

            WaitPageToLoad();
        }

        [Then(@"the tasks are imported to project")]
        public void ThenTheTasksAreImportedToProject()
        {
            var project = FindProjectByTitle(_projectTitle);
            _projectTitle = null;
            var tasks = project.AllTasks(ProductContext);
            Assert.AreNotEqual(0, tasks.Count());
        }

        [Given(@"I am on the create requirement page")]
        public void GivenIAmOnTheCreateRequirementPage()
        {
            _expectedChildren.Clear();
            Selenium.Open("/");
            Selenium.Click("link=创建需求");
            WaitPageToLoad();
        }

        [Given(@"Fill all necessary requirement properties")]
        public void GivenFillAllNecessaryRequirementProperties()
        {
            _requirementTitle = string.Format("Requirement_{0}", Guid.NewGuid());
            Selenium.Type("Requirement_Title", _requirementTitle);
            Selenium.Type("Requirement_AssignedTo", "HW-YISH-2\\Administrator");
            Selenium.Type("Requirement_BusinessValue", "2000");
            Selenium.Select("BelongsToMilestone.ID", string.Format("label={0}", _project.Title));
        }

        [When(@"I press create on requirement page")]
        public void WhenIPressCreateOnRequirementPage()
        {
            Selenium.Click("submit_btn");
            WaitPageToLoad();
        }

        [Given(@"Created some requirements/tasks previously")]
        public void GivenCreatedSomeRequirementsTasksPreviously()
        {
            _expectedChildren.Add(CreateTaskFromContext((Milestone)_project));
            _expectedChildren.Add(CreateRequirementFromContext((Milestone)_project));
        }

        [Given(@"Select some sub requirements on requirement page")]
        public void GivenSelectSomeSubRequirementsOnRequirementPage()
        {
            Selenium.Click("addChildren");
            WaitAjaxToFinish();
            Selenium.Click("selectReqs");
            WaitAjaxToFinish();

            foreach (var ticket in _expectedChildren)
            {
                if (ticket is Requirement)
                {
                    var path = string.Format("//input[@id='select_item_chk' and @value='{0}']", ticket.ID.ToString("D"));
                    Selenium.Click(path);
                }
            }

            Selenium.Click("//button[@type='button']");
            WaitAjaxToFinish();
        }

        [Given(@"Select some sub tasks on requirement page")]
        public void GivenSelectSomeSubTasksOnRequirementPage()
        {
            Selenium.Click("addChildren");
            WaitAjaxToFinish();
            Selenium.Click("selectTask");
            WaitAjaxToFinish();

            foreach (var ticket in _expectedChildren)
            {
                if (ticket is Task)
                {
                    var path = string.Format("//input[@id='select_item_chk' and @value='{0}']", ticket.ID.ToString("D"));
                    Selenium.Click(path);
                }
            }

            Selenium.Click("//button[@type='button']");
            WaitAjaxToFinish();
        }

        [Then(@"A requirement should be created")]
        public void ThenARequirementShouldBeCreated()
        {
            var actual = ProductContext.Requirements.Query.Single(r => r.Title == _requirementTitle);
            Assert.AreEqual(_project.ID, actual.BelongsToMilestoneId);
            Assert.AreEqual(2000, actual.BusinessValue);
        }

        [Then(@"Sub requirements are added to the new requirement")]
        public void ThenSubRequirementsAreAddedToTheNewRequirement()
        {
            var requirement = FindRequirementByTitle(_requirementTitle);
            foreach (var ticket in _expectedChildren)
            {
                if (ticket is Requirement)
                {
                    Assert.IsTrue(requirement.Children.Any(r => r.Title == ticket.Title), 
                        string.Format("requirement {0} is not added as sub requirements", ticket.ID));
                }
            }
        }

        [Then(@"Sub tasks are added to the new requirement")]
        public void ThenSubTasksAreAddedToTheNewRequirement()
        {
            var requirement = FindRequirementByTitle(_requirementTitle);
            foreach (var ticket in _expectedChildren)
            {
                if (ticket is Task)
                {
                    Assert.IsTrue(requirement.Children.Any(r => r.Title == ticket.Title), 
                        string.Format("task {0} is not added as sub tasks", ticket.ID));
                }
            }
        }

        [Given(@"Click create requirement link on the project details page")]
        public void GivenClickCreateRequirementLinkOnTheProjectDetailsPage()
        {
            Selenium.Open(string.Format("/Project/Details/{0}", _project.ID.ToString("D")));
            WaitPageToLoad();
            Selenium.Click("//div[@id='main']/p[1]/a[3]");
            WaitPageToLoad();
        }

        [Given(@"Created some sub requirements on requirement page")]
        public void GivenCreatedSomeSubRequirementsOnRequirementPage()
        {
            var rand = new Random();
            int childCount = rand.Next(3);
            childCount = childCount <= 0 ? 1 : childCount;
            Trace.WriteLine(string.Format("[GivenCreatedSomeSubRequirementsOnRequirementPage]: create {0} sub requirements", childCount));
            for (int i = 0; i < childCount; ++i)
                _expectedChildren.Add(CreateRequirementHelper((Milestone)_project));

            foreach (var requirement in _expectedChildren.OfType<Requirement>())
            {
                Trace.WriteLine(string.Format("[GivenCreatedSomeSubRequirementsOnRequirementPage] create new sub requirement: {0}", requirement.ID));
                Selenium.Click("addChildren");
                WaitAjaxToFinish();
                Selenium.Click("createReqs");
                WaitAjaxToFinish();
                Selenium.Type("//form[@id='child_editor']/fieldset/div[2]/input[2]", requirement.Title);
                Selenium.Type("//form[@id='child_editor']/fieldset/div[4]/input", requirement.AssignedTo);
                Selenium.Type("//input[@id='Requirement_BusinessValue' and @name='BusinessValue' and @value='']", requirement.BusinessValue.ToString());
                Selenium.Select("document.forms[1].elements[7]", string.Format("label={0}", requirement.BelongsToMilestone.Title));
                WaitAjaxToFinish();
                RandomThinkTime();

                Selenium.Click("//button[@type='button']");
            }
            WaitAjaxToFinish();
        }

        [Given(@"Created some sub tasks on requirement page")]
        public void GivenCreatedSomeSubTasksOnRequirementPage()
        {
            var rand = new Random();
            int tasksCount = rand.Next(3);
            tasksCount = tasksCount <= 0 ? 1 : tasksCount;
            Trace.WriteLine(string.Format("[GivenCreatedSomeSubTasksOnRequirementPage]: create {0} sub tasks", tasksCount));
            for (int i = 0; i < tasksCount; ++i)
                _expectedChildren.Add(CreateTaskHelper((Milestone)_project));

            foreach (var task in _expectedChildren.OfType<Task>())
            {
                Trace.WriteLine(string.Format("[GivenCreatedSomeSubTasksOnRequirementPage] create new sub task: {0}", task.ID));
                Selenium.Click("addChildren");
                WaitAjaxToFinish();
                Selenium.Click("createTask");
                WaitAjaxToFinish();
                Selenium.Type("Task_Title", task.Title);
                Selenium.Type("Task_AssignedTo", task.AssignedTo);
                Selenium.Click("Task_StartDate");
                Selenium.Click(string.Format("link={0}", task.StartDate.Value.Day));
                Selenium.Click("Task_DueDate");
                Selenium.Click(string.Format("link={0}", task.DueDate.Value.Day));
                Selenium.Select("document.forms[1].elements[9]", string.Format("label={0}", task.BelongsToMilestone.Title));
                WaitAjaxToFinish();
                RandomThinkTime();

                Selenium.Click("//button[@type='button']");
            }
            WaitAjaxToFinish();
        }
    }
}
